% Created 2022-05-04 周三 20:38
% Intended LaTeX compiler: xelatex
\documentclass[a4paper]{article}
                 \usepackage{graphicx}
                 \usepackage{xcolor}
                 \usepackage{xeCJK}
                 \usepackage{fixltx2e}
                 \usepackage{longtable}
                 \usepackage{float}        
                 \usepackage{tikz}         
                 \usepackage{wrapfig}      
                 \usepackage{latexsym,amssymb,amsmath}
                 \usepackage{textcomp}
                 \usepackage{bicaption}
                 \usepackage{listings}     
                \usepackage{marvosym}     
                \usepackage{textcomp}     
                \usepackage{latexsym}     
                \usepackage{natbib}
                \usepackage{indentfirst}
		\usepackage{hyperref}
                \usepackage{geometry}
                \usepackage{minted}
                \setCJKmainfont{宋体}
                \setlength{\parindent}{2em}
                \usepackage{color}
                \usepackage{fancyhdr}
\pagestyle{fancy}
\fancyhead[R]{\footnotesize{《Android 物联网应用程序开发》 广西职业师范学院实验教学指导书}}
\geometry{a4paper,left=2.5cm,right=2.5cm,top=2cm,bottom=2cm}
\setCJKmainfont{仿宋}
\setCJKsansfont{Microsoft YaHei}
\setCJKmonofont{Microsoft YaHei}

            \lstset{
  columns=fixed,       
  breaklines=true, breakautoindent=true,breakindent=4em,
  numbers=left,                                        % 在左侧显示行号
  frame=none,                                          % 不显示背景边框
  backgroundcolor=\color[RGB]{245,245,244},            % 设定背景颜色
  keywordstyle=\color[RGB]{40,40,255},                 % 设定关键字颜色
  numberstyle=\footnotesize\color{darkgray},           % 设定行号格式
  commentstyle=\it\color[RGB]{0,96,96},                % 设置代码注释的格式
  stringstyle=\rmfamily\slshape\color[RGB]{128,0,0},   % 设置字符串格式
  showstringspaces=false,                              % 不显示字符串中的空格
  language=java,                                        % 设置语言
}

\usemintedstyle{emacs}
    \setminted{%
        autogobble,% automatically remove the spaces to the left of the code
        linenos=true,% show line numbers
        fontsize=\small,% smaller font size
        % escapeinside=@@,% insert latex code between @ and @
        frame=lines,% frame styles: none or lines
        % frame=none,
        numbers=none,% show line numbers on: left, right, both or none
        mathescape=true,% insert math code
	breaklines=true,
    }%
    \setmintedinline{%
        fontsize=\smallsize,
    }%
\date{\today}
\title{实验八: 多线程练习}
\hypersetup{
 pdfauthor={},
 pdftitle={实验八: 多线程练习},
 pdfkeywords={},
 pdfsubject={},
 pdfcreator={Emacs 27.1 (Org mode 9.3.8)}, 
 pdflang={English}}
\begin{document}

\maketitle
\tableofcontents

\newpage

\section{实验目的}
\label{sec:orga1b5e6c}
\begin{itemize}
\item 掌握 AsynTask 异步线程类的使用
\end{itemize}
\section{实验设备和器件}
\label{sec:org7d38d3d}
\begin{itemize}
\item PC
\item 内存要求 8G 以上
\end{itemize}
\section{实验内容}
\label{sec:orgf6eb374}
\subsection{实训一}
\label{sec:org0d4dc1b}
\subsubsection{实训步骤}
\label{sec:orgaa65e1c}
\begin{itemize}
\item step1: 创建一个界面并按下图添加相关组件
\begin{center}
\includegraphics[width=0.5\textwidth]{img/1.jpg}
\end{center}

\item step2: 初始化相关组件
\lstset{language=java,label= ,caption= ,captionpos=b,numbers=none}
\begin{lstlisting}
private Button btn;
private TextView tv;
private static final String TAG = "AsyntaskTest";
private ProgressBar pb;
private static int progress = 0;
\end{lstlisting}
\lstset{language=java,label= ,caption= ,captionpos=b,numbers=none}
\begin{lstlisting}
btn = findViewById(R.id.button2);
tv = findViewById(R.id.textView);
pb = findViewById(R.id.progressBar);
pb.setMax(100);
pb.setProgress(0);
\end{lstlisting}
\item step3: 定义一个类MyTask,让它继承AsyncTask,并重构以下几个方法,这几个方法的描述如下:
\begin{center}
\begin{tabular}{lll}
\hline
方法 & 调用顺序及其功能 & 执行位置\\
\hline
onPreExecute & 线程启动前调用,在execute()被调用后首先执行 & 主线程执行\\
doInBackground & 线程启动，在后台运行该线程,负责耗时的运算 & 子线程执行\\
onPostExecute & 线程结束后调用该方法 & 主线程执行\\
onCancelled & 线程被取消后调用该方法 & 主线程执行\\
onProgressUpdate & 调用publishProgress执行，进度信息更新到UI & 主线程执行\\
\hline
\end{tabular}
\end{center}

\item step4: 在对应的方法中添加事务，完成MyTask类
\lstset{language=java,label= ,caption= ,captionpos=b,numbers=none}
\begin{lstlisting}
      class MyTask extends AsyncTask<String,Integer,String>
    {
	@Override
	protected void onPreExecute() {
	    super.onPreExecute();
	    Log.i(TAG, "onPreExecute() called");
	    tv.setText("loading...");
	}

	@Override
	protected void onPostExecute(String s) {
	    super.onPostExecute(s);
	    Log.i(TAG, "onPostExecute(Result result) called");
	    tv.setText(s);
	}

	@Override
	protected void onCancelled() {
	    super.onCancelled();
	    Log.i(TAG, "onCancelled() called");
	    tv.setText("cancelled");
	}

	@Override
	protected String doInBackground(String... strings) {
	    while (progress < 100)
	    {
		try {
		    progress++;
		    Thread.sleep(500);
		    publishProgress(progress);
		} catch (InterruptedException e) {
		    e.printStackTrace();
		}

	    }
	    return "finished";
	}

	@Override
	protected void onProgressUpdate(Integer... values) {
	    super.onProgressUpdate(values);
	    pb.setProgress(values[0]);
	    tv.setText(values[0]+"%");
	}
    }
}
\end{lstlisting}
\item step5:  在主界面为按钮添加监听
\lstset{language=java,label= ,caption= ,captionpos=b,numbers=none}
\begin{lstlisting}
btn.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View view) {
	  MyTask myTask = new MyTask();
	  myTask.execute();
      }
  });
\end{lstlisting}
\end{itemize}


\subsection{实训二}
\label{sec:org2eda96f}
\subsubsection{实训步骤}
\label{sec:orgd82996a}
\begin{enumerate}
\item 连接到网络
\label{sec:org018fa35}
该实训要实现一个简单的连接到网络的程序。
它提供了一些我们在创建即使最简单的网络连接程序时也应该遵循的最佳示例。
请注意，想要执行本次实训的网络操作首先需要在程序的 manifest 文件中添加以下权限：
\lstset{language=XML,label= ,caption= ,captionpos=b,numbers=none}
\begin{lstlisting}
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
\end{lstlisting}
\item 按照布局图创建xml布局组件并调整好布局
\label{sec:org03bf88d}
\begin{center}
\includegraphics[width=0.5\textwidth]{img/2.jpg}
\end{center} 

\item 选择一个http client
\label{sec:orgd1c42d7}
选择一个http client,高版本推荐HttpURLConnection
\item 检查网络连接
\label{sec:org078ec54}
在我们的 app 尝试连接网络之前，应通过函数 getActiveNetworkInfo() 和 isConnected()
检测当前网络是否可用。请注意，设备可能不在网络覆盖范围内，或者用户可能关闭 Wi-Fi
与移动网络连接。关于这部分的更多详情，请参考管理网络的使用情况。
\lstset{language=java,label= ,caption= ,captionpos=b,numbers=none}
\begin{lstlisting}
ConnectivityManager connMgr = (ConnectivityManager)
    getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isConnected()) {
    // 以下编写获取数据的代码
} else {
    // 网络连接错误 
}
\end{lstlisting}
\item 在一个单独的线程中执行网络操作
\label{sec:org8aa2891}
网络操作会遇到不可预期的延迟。为了避免造成不好的用户体验，总是在 UI 线程之外
单独的线程中执行网络操作。AsyncTask 类提供了一种简单的方式来处理这个问题。
在下面的代码示例中,DownloadWebpageTask 是 AsyncTask 的子类，它实现了下面两个方法:
doInBackground() 执行 downloadUrl() 方法。它以网页的 URL 作为参数，方法 downloadUrl()
获取并处理网页返回的数据。执行完毕后，返回一个结果字符串。
onPostExecute() 接收结果字符串并把它显示到 UI 上。
\lstset{language=java,label= ,caption= ,captionpos=b,numbers=none}
\begin{lstlisting}
    public class HttpTest extends AppCompatActivity {
    private Button btn;
    private EditText mutilineEdit;
    String stringUrl = "https://www.baidu.com";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.activity_http_test);
	mutilineEdit = findViewById(R.id.editText);
	btn = findViewById(R.id.button3);
	btn.setOnClickListener(new View.OnClickListener() {
	    @Override
	    public void onClick(View view) {
		ConnectivityManager connMgr = (ConnectivityManager)
			getSystemService(Context.CONNECTIVITY_SERVICE);
		NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
		if (networkInfo != null && networkInfo.isConnected()) {
		    // 获取数据
		    Log.d("TAG","可以连接网络");
		    new DownloadWebpageText().execute(stringUrl);
		} else {
		    // 网络错误
		}
	    }
	});
    }
}
\end{lstlisting}
DownloadWebpageText类
\lstset{language=java,label= ,caption= ,captionpos=b,numbers=none}
\begin{lstlisting}
    class DownloadWebpageText extends AsyncTask<String,Integer,String>
{
    @Override
    protected void onPreExecute() {
	super.onPreExecute();
    }

    @Override
    protected void onPostExecute(String info) {
	super.onPostExecute(info);
	Log.d("TAG",info);
	mutilineEdit.setText(info);
    }

    @Override
    protected String doInBackground(String[] url) {
	//String url = (String)(objects[0]);
	try {
	    return downloadUrl(url[0]);
	} catch (IOException e) {
	    return "Unable to retrieve web page. URL may be invalid.";
	}

    }

   private String downloadUrl(String myurl) throws IOException {
	InputStream is = null;
	// Only display the first 500 characters of the retrieved
	// web page content.
	int len = 500;

	try {
	    URL url = new URL(myurl);
	    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
	    conn.setReadTimeout(10000 /* milliseconds */);
	    conn.setConnectTimeout(15000 /* milliseconds */);
	    conn.setRequestMethod("GET");
	    conn.setDoInput(true);
	    // 开始连接
	    conn.connect();
	    int response = conn.getResponseCode();
	    Log.d("TAG", "The response is: " + response);
	    is = conn.getInputStream();

	    // 将输入流转换成字符串
	    String contentAsString = readIt(is, len);
	    return contentAsString;

	    // 结束时关闭输入流
	} finally {
	    if (is != null) {
		is.close();
	    }
	}
    }

       public String readIt(InputStream stream, int len) throws IOException, UnsupportedEncodingException {
	    Reader reader = null;
	    reader = new InputStreamReader(stream, "UTF-8");
	    char[] buffer = new char[len];
	    reader.read(buffer);
	    return new String(buffer);
	}
}
\end{lstlisting}
\end{enumerate}

\subsection{总结}
\label{sec:org7dd825d}
\begin{itemize}
\item 上面这段代码的事件顺序如下:
\begin{itemize}
\item 当用户点击按钮时调用 onClick()，app 将指定的 URL 传给 AsyncTask 的子类 DownloadWebpageTask。
\item AsyncTask 的 doInBackground() 方法调用 downloadUrl() 方法。
\item downloadUrl() 方法以一个 URL 字符串作为参数，并用它创建一个 URL 对象。
\item 这个 URL 对象被用来创建一个 HttpURLConnection。
\item 一旦建立连接，HttpURLConnection 对象将获取网页的内容并得到一个 InputStream。
\item InputStream 被传给 readIt() 方法，该方法将流转换成字符串。
\item 最后，AsyncTask 的 onPostExecute() 方法将字符串展示在 main activity 的 UI 上。
\end{itemize}
\end{itemize}
\end{document}